package com.element.oauth2.server.handler;

import com.common.core.constant.SecurityHeader;
import com.common.core.exception.code.SecurityErrorCode;
import com.common.core.results.SingleResult;
import com.common.core.results.VoidResult;
import com.element.oauth2.model.co.TokenCO;
import com.element.oauth2.model.co.TokenRefreshCO;
import com.element.oauth2.utils.ResponseUtil;
import io.netty.util.internal.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Instant;

public class TokenAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException {
        logger.info("TokenAuthenticationSuccessHandler.onAuthenticationSuccess");
        OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) authentication;
        OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
        if (null == accessToken || StringUtil.isNullOrEmpty(accessToken.getTokenValue())) {
            ResponseUtil.writeJson(response, VoidResult.failed(SecurityErrorCode.A_INTERNAL_AUTHENTICATION_SERVICE_EXCEPTION));
            return;
        }
        OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
        if (null != refreshToken && !StringUtil.isNullOrEmpty(refreshToken.getTokenValue())) {
            TokenRefreshCO refreshCO = new TokenRefreshCO();
            refreshCO.setAccessToken(accessToken.getTokenValue());
            refreshCO.setRefreshToken(refreshToken.getTokenValue());
            refreshCO.setExpiresIn(expiresIn(accessToken.getExpiresAt()));
            refreshCO.setTokenHeader(SecurityHeader.AUTH_SECURITY_HEADERS);
            refreshCO.setTokenType(SecurityHeader.AUTH_SECURITY_VALUE);
            ResponseUtil.writeJson(response, SingleResult.of(refreshCO));
        } else {
            TokenCO tokenCO = new TokenCO();
            tokenCO.setAccessToken(accessToken.getTokenValue());
            tokenCO.setExpiresIn(expiresIn(accessToken.getExpiresAt()));
            tokenCO.setTokenHeader(SecurityHeader.AUTH_SECURITY_HEADERS);
            tokenCO.setTokenType(SecurityHeader.AUTH_SECURITY_VALUE);
            ResponseUtil.writeJson(response, SingleResult.of(tokenCO));
        }
        // 无状态 注意删除 context 上下文的信息
        SecurityContextHolder.clearContext();
    }

    private long expiresIn(Instant instant) {
        if (null != instant) {
            long startTime = System.currentTimeMillis() / 1000;
            long expiresIn = instant.getEpochSecond();
            return expiresIn - startTime;
        } else {
            return 0L;
        }
    }
}
